package nl.windgazer.arachne.services;

import java.util.ArrayList;
import java.util.HashMap;

import nl.windgazer.arachne.util.HtmlHeadBlocks;

import org.apache.log4j.Logger;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.dom.Element;


/**
 * An add-on to T5s' own RenderSupport. Allowing a developer to add ScriptBlocks and StyleBlocks
 * to the head of a page, for when a script can't wait for the page to finish loading thus making
 * the initScript and addScript methods unusable.
 * 
 * @author mreuring
 */
public class ArachneRenderSupportImp implements ArachneRenderSupport {

	final static Logger logger = Logger.getLogger(ArachneRenderSupportImp.class);

	private static class MetaVO {
		private final String keyValue;
		private final String keyName;
		private final String content;
		public MetaVO(final String kv, final String content, final String kn) {
			this.keyValue = kv;
			this.content = content;
			this.keyName = kn;
		}
	}

	private final static char NEWLINE = '\n';

	private final static String LINK = "link";

	private final static String LINK_REL = "rel";

	private final static String LINK_HREF = "href";

	private final static String META = "meta";

	private final static String META_NAME = "name";

	private final static String META_CONTENT = "content";

	private final StringBuffer firstscripts = new StringBuffer();

	private final StringBuffer scripts = new StringBuffer();

	private final StringBuffer styles = new StringBuffer();

	private final ArrayList<String> cufons = new ArrayList<String>();

	private final HashMap<String, String> links = new HashMap<String, String>();

	private final HashMap<String, MetaVO> metas = new HashMap<String, MetaVO>();

	private boolean cufonInit = false;

	public void addScriptHead(String script) {
		addScriptHead(script, false);
	}

	public void addScriptHead(String script, boolean beforeLibraries) {
		if (beforeLibraries) {
			firstscripts.append(script);
			firstscripts.append(NEWLINE);
		} else {
			scripts.append(script);
			scripts.append(NEWLINE);
		}
	}

	public void addStyleHead(String style) {
		styles.append(style);
		styles.append(NEWLINE);
	}

	public void addCufonReplace(String cufon) {
		if (!cufons.contains(cufon)) cufons.add(cufon);
	}

	public void writeMarkup(MarkupWriter writer) {

		for (final String replacement : cufons) {
			final String[] parts = replacement.split("\\|");
			final StringBuffer sb = new StringBuffer();
			sb.append("Cufon.replace('").append(parts[0]).append("'");
			if (parts.length > 1) {
				sb.append(", { fontFamily: '").append(parts[1]).append("' }");
			}
			sb.append(");");
			addScriptHead(sb.toString());
		}
//		if (cufons.size() > 0) {
//			addScriptHead("window.setTimeout(function(){Cufon.now();},0);");
//		}

		final Element firstScriptElement = HtmlHeadBlocks.writeScriptBlock(firstscripts.toString(), writer.getDocument());
		if (firstScriptElement!=null) {
			firstScriptElement.moveToTop(firstScriptElement.getContainer());
	
			HtmlHeadBlocks.writeScriptBlock(scripts.toString(), writer.getDocument());
			HtmlHeadBlocks.writeStyleBlock(styles.toString(), writer.getDocument());
			
			final Element head = HtmlHeadBlocks.getHead(writer.getDocument());
	        if (head != null) {
	        	for (final String key: links.keySet()) {
	        		head.element(LINK, LINK_REL, key, LINK_HREF, links.get(key));
	        	}
	        	for (final String key: metas.keySet()) {
	        		final MetaVO mvo = metas.get(key);
	        		head.element(META, mvo.keyName, mvo.keyValue, META_CONTENT, mvo.content);
	        	}
	        }
		} else {
			logger.debug("Skipped rendering script, HTML was found to be incomplete, no <head> element!");
		}
	}

	public void addLink(String rel, String href) {
		links.put(rel, href);
	}

	public void addMetaTag(String keyValue, String content, String keyName) {
		metas.put(keyValue, new MetaVO(keyValue, content, keyName));
	}

	public void addMetaTag(String keyValue, String content) {
		addMetaTag(keyValue, content, META_NAME);
	}

	public void setCufonInit(boolean cufonInit) {
		this.cufonInit = cufonInit;
	}

	public boolean isCufonInit() {
		return cufonInit;
	}

}
